﻿using CsvHelper;
using DataAchive.Helper;
using DataAchive.Model;
using DataAchive.Model.Payloads;
using DataAchive.Model.ViewModels;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using OpenCvSharp;
using SoftCommon;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using System.Xml;

namespace DataAchive
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : System.Windows.Window
    {
        private M_QueryBuilder queryHelper = new M_QueryBuilder();
        private DispatcherTimer timer;
        public MainWindow()
        {



            SoftCommon.Log.Write("程序启动:");
            InitializeComponent();
            MainViewModel mainWindowModel = new MainViewModel() { };
            DataContext = mainWindowModel;
            this.DataContext = mainWindowModel;
            //queryHelper.SetTable();
            Start();
            //tb_log.TextChanged += UpdateTextBoxHeight;

            SoftCommon.Log.Write($"项目启动后台开启定时图片压缩任务：");
            ImageCompression();
            // 创建一个 DispatcherTimer 实例
            SoftCommon.Log.Write($"读取定时器配置");
            XmlNode compassNode = Setting.GetXmlNode(@"setting/ImageCompass/TimeSpan");
            SoftCommon.Log.Write($"创建定时器，写入事件");
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(Convert.ToInt32(compassNode.InnerText)); // 设置定时器间隔
            timer.Tick += Timer_Tick; // 定时器触发事件的处理方法
            timer.Start(); // 启动定时器

            
        }

        private static HttpListener httpobj;
        #region 开始
        /// <summary>
        /// 开始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="Exception"></exception>
        //private void Btn_Start_Click(object sender, RoutedEventArgs e)
        private void Start()
        {

            try
            {
                //提供一个简单的、可通过编程方式控制的 HTTP 协议侦听器。此类不能被继承。
                httpobj = new HttpListener();
                string ip = Setting.GetElementTextValue("IP").Split(':')[0];
                string port = Setting.GetElementTextValue("IP").Split(':')[1];
                string address = Setting.GetElementTextValue("Route");
                //定义url及端口号，通常设置为配置文件
                httpobj.Prefixes.Add($"http://{ip}:{port}/{address}/");
                //httpobj.Prefixes.Add($"http://{TextBox_IP.Text}:{TextBox_Port.Text}/{TextBox_Address.Text}/");
                //启动监听器
                if (httpobj != null && !httpobj.IsListening)
                {
                    httpobj.Start();
                    SoftCommon.Log.Write("服务端启动！监听服务中：");
                    if (httpobj != null && httpobj.IsListening)
                    {
                        MainViewModel mainWindowModel = this.DataContext as MainViewModel;
                        mainWindowModel.IsStartButtonEnabled = !httpobj.IsListening;
                        mainWindowModel.IsStopButtonEnabled = httpobj.IsListening;
                        mainWindowModel.LabelVisibity = Visibility.Visible;
                    }

                    //异步监听客户端请求，当客户端的网络请求到来时会自动执行Result委托
                    //该委托没有返回值，有一个IAsyncResult接口的参数，可通过该参数获取context对象
                    SoftCommon.Log.Write("服务端初始化");
                    httpobj.BeginGetContext(Result, null);
                    SoftCommon.Log.Write("服务端初始化完毕，等待客户端请求:");
                    tb_log.AppendText($"服务端初始化完毕，正在等待客户端请求,时间：{DateTime.Now.ToString()}\r\n");
                }
                else
                {
                    SoftCommon.Log.Write("服务端启动！");
                    tb_log.AppendText($"服务端已启动！\r\n");
                }
            }
            catch (Exception ex)
            {
                SoftCommon.Log.Write(LogType.Error, ex.Message);
            }

        }
        #region 监听服务
        /// <summary>
        /// 监听服务，有新的请求就会进入
        /// </summary>
        /// <param name="ar"></param>
        private void Result(IAsyncResult ar)
        {

            //当接收到请求后程序流会走到这里
            // 如果 HttpListener 已经关闭，则直接返回
            if (httpobj == null || !httpobj.IsListening)
                return;

            Dispatcher.Invoke(() => tb_log.AppendText($"接到新的请求,时间：{DateTime.Now.ToString()}\r\n"));
            SoftCommon.Log.Write("接收到客户端请求！获取解析请求对象");
            //获得context对象
            var context = httpobj.EndGetContext(ar);
            var request = context.Request;
            var response = context.Response;
            ////如果是js的ajax请求，还可以设置跨域的ip地址与参数
            context.Response.ContentType = "text/plain;charset=UTF-8";//告诉客户端返回的ContentType类型为纯文本格式，编码为UTF-8
            context.Response.AddHeader("Content-type", "text/plain");//添加响应头信息
            context.Response.ContentEncoding = Encoding.UTF8;
            object returnObj = null;//定义返回客户端的信息
            if (request.HttpMethod == "POST" && request.InputStream != null)
            {
                //处理客户端发送的请求并返回处理信息
                SoftCommon.Log.Write("处理客户端发送的请求并返回处理信息");
                returnObj = HandleRequest(request, response);
                SoftCommon.Log.Write("客户端请求处理成功！");
            }
            else
            {
                SoftCommon.Log.Write("不是post请求或者传过来的数据为空！");
                returnObj = $"不是post请求或者传过来的数据为空";
            }
            var returnByteArr = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(returnObj));//设置客户端返回信息的编码
            try
            {
                using (var stream = response.OutputStream)
                {
                    //把处理信息返回到客户端
                    SoftCommon.Log.Write("处理信息返回给客户端");
                    stream.Write(returnByteArr, 0, returnByteArr.Length);
                    SoftCommon.Log.Write("返回到客户端成功");
                }
            }
            catch (Exception ex)
            {
                SoftCommon.Log.Write(LogType.Error, "处理信息返回给客户端失败，" + ex.Message);
                Dispatcher.Invoke(() => tb_log.AppendText($"异常：{ex.ToString()}\r\n"));
            }
            Dispatcher.Invoke(() => tb_log.AppendText($"请求处理完成,时间：{DateTime.Now.ToString()}\r\n"));

            //继续异步监听
            httpobj.BeginGetContext(Result, null);
            SoftCommon.Log.Write("请求处理结束，继续监听服务！");
        }

        /// <summary>
        /// 处理请求和响应信息
        /// </summary>
        /// <param name="request"></param>
        /// <param name="response"></param>
        /// <returns></returns>
        private Data4SaveResponse HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
        {
            string data = null;
            Data4SaveResponse result = null;
            try
            {
                var byteList = new List<byte>();
                var byteArr = new byte[2048];
                int readLen = 0;
                int len = 0;
                //接收客户端传过来的数据并转成字符串类型
                SoftCommon.Log.Write("接收客户端传过来的数据并转成字符串类型");
                do
                {
                    readLen = request.InputStream.Read(byteArr, 0, byteArr.Length);
                    len += readLen;
                    byteList.AddRange(byteArr);
                } while (readLen != 0);
                data = Encoding.UTF8.GetString(byteList.ToArray(), 0, len);
                SoftCommon.Log.Write("字符串处理成功！");
                //保存请求json文件
                CreateFile(data);

                //获取得到数据data可以进行其他操作
                result = Data4Save(JsonConvert.DeserializeObject<Data4SaveRequest>(data));


            }
            catch (Exception ex)
            {
                SoftCommon.Log.Write(LogType.Error, "在接收数据时发生错误:" + ex.Message);
                response.StatusDescription = "404";
                response.StatusCode = 404;
                Dispatcher.Invoke(() => tb_log.AppendText($"在接收数据时发生错误:{ex.ToString()}\r\n"));
                return new Data4SaveResponse() { recieved = $"在接收数据时发生错误:{ex.ToString()}" };//把服务端错误信息直接返回可能会导致信息不安全，此处仅供参考
            }
            response.StatusDescription = "200";//获取或设置返回给客户端的 HTTP 状态代码的文本说明。
            response.StatusCode = 200;// 获取或设置返回给客户端的 HTTP 状态代码。
            Dispatcher.Invoke(() => tb_log.AppendText($"接收数据完成,时间：{DateTime.Now.ToString()}\r\n"));
            return result;
        }
        #endregion

        #region 数据处理
        /// <summary>
        /// 处理请求，响应信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Data4SaveResponse Data4Save(Data4SaveRequest request)
        {
            Data4SaveResponse response = new Data4SaveResponse();
            response.messagetype = request.messagetype;
            response.lotid = request.lotid;
            response.recieved = "ok";
            Task.Run(() =>
            {
                Save(request);
            }).Wait();
            return response;
        }
        /// <summary>
        /// 数据库保存
        /// </summary>
        /// <param name="request"></param>
        public void Save(Data4SaveRequest request)
        {
            SoftCommon.Log.Write("解析请求信息保存数据库！");
            //机台信息
            AChiveSite site = GetSiteInfo(request);

            List<AChiveSite> siteList = queryHelper.GetModelList(new AChiveSite() { Line_Id = site.Line_Id, Equipment_Id = site.Equipment_Id, IP = site.IP });
            if (siteList != null && siteList.Any())
            {
                site = siteList[0];
            }
            else
            {
                //插入一条site信息并获取到siteId
                site.Id = queryHelper.Insert(site);
            }
            int siteId = site.Id ?? 0;

            SoftCommon.Log.Write($"写入机台信息,获取机台ID：{siteId}");
            //要插入的info列表
            List<AChiveInfo> aChiveInfoList = new List<AChiveInfo>();
            if (request.el_info != null)
            {
                //ng   //el_info type=0
                AChiveNG elNG = new AChiveNG();
                elNG.Lot_Id = request.lotid;
                elNG.Checked = 0;
                elNG.Date = DateTime.Now;
                elNG.Type = 0;
                elNG.Site_Id = siteId;
                elNG.Finish_Time = DateTime.Now;
                elNG.Manua_Result = request.el_info?.manually_result;
                elNG.Mes_Check = 0;

                elNG.Is_Timeout= request.Is_Timeout;
                elNG.TimeoutClassify=request.TimeoutClassify;
                //插入一条ng信息并获取到ngId
                int elNGId = queryHelper.Insert(elNG);
                SoftCommon.Log.Write($"NG写入EL信息,获取EL_ID：{elNGId}");
                //el_info列表
                request.el_info.location.ForEach(location =>
                {
                    GetAchiveList(location, aChiveInfoList, elNGId);
                });
            }
            if (request.vi_info != null)
            {
                //ng   vi_info type=1
                AChiveNG viNG = new AChiveNG();
                viNG.Lot_Id = request.lotid;
                viNG.Checked = 0;
                viNG.Date = DateTime.Now;
                viNG.Type = 1;
                viNG.Site_Id = siteId;
                viNG.Finish_Time = DateTime.Now;
                viNG.Manua_Result = request.vi_info?.manually_result;
                viNG.Mes_Check = 0;

                viNG.Is_Timeout = request.Is_Timeout;
                viNG.TimeoutClassify = request.TimeoutClassify;
                //插入一条ng信息并获取到ngId
                int viNGId = queryHelper.Insert(viNG);
                SoftCommon.Log.Write($"NG写入VI信息,获取VI_ID：{viNGId}");
                //vi_info 列表
                request.vi_info?.location.ForEach(location =>
                {
                    GetAchiveList(location, aChiveInfoList, viNGId);
                });
            }

            //批量Info插入
            queryHelper.InsertMany(aChiveInfoList);
            SoftCommon.Log.Write($"批量写入INFO,共{aChiveInfoList.Count}条");
        }
        /// <summary>
        /// 获取机台信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private AChiveSite GetSiteInfo(Data4SaveRequest request)
        {
            AChiveSite site = new AChiveSite();
            if (request != null)
            {
                EL_Info info = new EL_Info();
                if (request.el_info != null)
                {
                    info = request.el_info;
                }
                else
                {
                    if (request.vi_info != null)
                    {
                        info = request.vi_info;
                    }
                }
                if (info != null)
                {
                    site.Line_Id = info.lineid;
                    site.Equipment_Id = info.equipmentid;
                    site.IP = request.client_ip;
                    site.Row_Number = info.row_number;
                    site.Row_Type = info.row_type;
                    site.Row_Order = Convert.ToInt32(info.row_order).ToString();
                    site.Colum_Number = info.column_number;
                    site.Colum_Type = info.column_type;
                    site.Colum_Order = Convert.ToInt32(info.column_order).ToString();
                    site.Top_Bottom_Margin = info.TopBottomMargin;
                    site.Left_Right_Margin = info.LeftRightMargin;
                    site.Shift_Start_Time = info.ShiftStartTime;
                    site.Shiftings = info.Shiftings;
                    site.Cuttent_Shift = info.CurrentShift;
                }
            }
            return site;
        }

        /// <summary>
        /// 获取Achive列表
        /// </summary>
        /// <param name="location"></param>
        /// <param name="aChiveInfoList"></param>
        /// <param name="ngId"></param>
        private static void GetAchiveList(Location location, List<AChiveInfo> aChiveInfoList, int ngId)
        {
            AChiveInfo info = new AChiveInfo();
            info.Classify = location.Classify;
            info.NG_Id = ngId;
            info.PX = location.PX;
            info.PY = location.PY;
            info.Width = location.PX;
            info.Height = location.PX;
            info.PX = location.PX;
            info.Cell_Location = "";
            info.Creator = "";
            aChiveInfoList.Add(info);
        }



        /// <summary>
        /// 请求json文件保存
        /// </summary>
        /// <param name="data"></param>
        public void CreateFile(string data)
        {
            // 检查文件夹是否存在，不存在则创建
            string path = System.Environment.CurrentDirectory + @"\JsonFile";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            // 检查文件是否存在，不存在则创建
            string fileName = $"Request{DateTime.Now.ToString("yyyyMMddHHmmss")}.json";
            string filePath = System.IO.Path.Combine(path, fileName);
            if (!File.Exists(filePath))
            {
                // 将 Person 对象序列化为 JSON 字符串
                string json = data;

                SoftCommon.Log.Write("请求字符串保存Json文件！");
                // 将 JSON 字符串写入文件
                File.WriteAllText(filePath, json);

                SoftCommon.Log.Write("Json文件保存成功！");
                Dispatcher.Invoke(() => tb_log.AppendText($"Json文件写入成功!\r\n"));
            }
        }
        #endregion
        #endregion

        #region 结束
        /// <summary>
        /// 关闭服务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="Exception"></exception>
        private void Btn_Stop_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                //关闭监听器
                if (httpobj != null && httpobj.IsListening)
                {
                    httpobj.Close();
                    if (httpobj == null || !httpobj.IsListening)
                    {
                        MainViewModel mainWindowModel = this.DataContext as MainViewModel;
                        mainWindowModel.IsStartButtonEnabled = !httpobj.IsListening;
                        mainWindowModel.IsStopButtonEnabled = httpobj.IsListening;
                        mainWindowModel.LabelVisibity = Visibility.Hidden;
                        httpobj = null; // 设置为 null，表示对象已经释放
                        SoftCommon.Log.Write($"停止服务端监听");
                        tb_log.AppendText($"服务端已停止监听,时间：{DateTime.Now.ToString()}\r\n");
                    }
                    else
                    {
                        tb_log.AppendText($"服务端未停止，请重试！\r\n");
                    }
                }
            }
            catch (Exception ex)
            {
                SoftCommon.Log.Write($"停止服务端监听失败{ex.Message}");
            }

        }

        #endregion


        #region 查询
        private static NgInfoWindow ngInfoWindow;
        /// <summary>
        /// 查询按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ViewButton_Click(object sender, RoutedEventArgs e)
        {
            if (ngInfoWindow == null || !ngInfoWindow.IsVisible)
            {
                SoftCommon.Log.Write($"点击查询按钮，打开查询界面！");
                ActivatorHelper.GetInstance<NgInfoWindow>(ref ngInfoWindow);
                ngInfoWindow.Closed += (s, eventArgs) => ngInfoWindow = null; // 当 SecondWindow 关闭时释放资源
                ngInfoWindow.Show();
            }
            else
            {
                ngInfoWindow.Activate(); // 如果 SecondWindow 已经存在，则激活它
            }
        }

        #endregion


        #region 图像压缩
        /// <summary>
        /// 计时器任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Tick(object sender, EventArgs e)
        {
            //Task.Run(() =>
            //{
            // 定时器触发事件的处理逻辑
            // 在这里执行你想要执行的定时任务
            // 例如更新UI、处理数据、发送请求等操作
            //Console.WriteLine("定时任务正在运行...");
            ImageCompression();
            //});
        }

        /// <summary>
        /// 压缩图片
        /// </summary>
        private void ImageCompression()
        {
            SoftCommon.Log.Write($"读取图片压缩配置");
            XmlNode compassNode = Setting.GetXmlNode(@"setting/ImageCompass");
            string sourcePath = compassNode.SelectSingleNode(@"ImageSourcePath").InnerText;
            string outPutPath = compassNode.SelectSingleNode(@"OutputImagePath").InnerText;
            string pixelWidth = compassNode.SelectSingleNode(@"PixelWidth").InnerText;

            // 匹配日期格式化字符串的正则表达式
            string pattern = @"(yyyy|yy|MM|dd|YYYY|YY|DD)";
            //string pattern = @"(yyyy/MM/dd|dd-MM-yyyy)";

            // 使用正则表达式匹配字符串
            MatchCollection sourcePathMatches = Regex.Matches(sourcePath, pattern);
            MatchCollection outPutPathMatches = Regex.Matches(outPutPath, pattern);
            if (sourcePathMatches != null && sourcePathMatches.Count > 0)
            {
                string sourceReplace = sourcePath.Substring(sourcePathMatches[0].Index, 10);
                string outputReplace = outPutPath.Substring(outPutPathMatches[0].Index, 10);
                string sourceFormat = sourceReplace.Replace("YYYY", "yyyy").Replace("DD", "dd");
                string outputFormat = outputReplace.Replace("YYYY", "yyyy").Replace("DD", "dd");
                sourcePath = sourcePath.Replace(sourceReplace, DateTime.Now.Date.ToString(sourceFormat));
                outPutPath = outPutPath.Replace(outputReplace, DateTime.Now.Date.ToString(outputFormat));
            }

            //判断文件夹是否存在
            if (!Directory.Exists(sourcePath))
                Directory.CreateDirectory(sourcePath);

            if (!Directory.Exists(outPutPath))
                Directory.CreateDirectory(outPutPath);

            string[] imageExtensions = { ".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff" };
            // 获取文件夹内所有图片文件（包含子文件夹）
            string[] files = FileHelper.ListAllImageFiles(sourcePath, imageExtensions);
            //获取已压缩的图片（包含子文件夹）
            string[] hasFiles = FileHelper.ListAllImageFiles(outPutPath, imageExtensions);
            SoftCommon.Log.Write($"读取图片列表，并压缩保存");
            // 遍历文件并压缩
            foreach (string file in files)
            {
                //判断文件是否存在
                if (hasFiles.Any(s => s.Replace(outPutPath, "") == file.Replace(sourcePath, "")))
                    continue;
                string fileName = System.IO.Path.GetFileName(file);
                SoftCommon.Log.Write($"获取到图片：{fileName}");
                string filePath = file.Replace(sourcePath, outPutPath);// FileHelper.GetFileName(outPutPath, fileName);
                var childFolder = Path.GetDirectoryName(filePath);
                //判断子文件夹是否存在
                if (!Directory.Exists(childFolder)) Directory.CreateDirectory(childFolder);
                // 读取原始图像
                Mat originalImage = Cv2.ImRead(file, ImreadModes.Color);

                // 调整图像大小
                int targetWidth = Convert.ToInt32(pixelWidth); // 目标宽度
                int targetHeight = (int)(originalImage.Rows * ((double)targetWidth / originalImage.Cols)); // 根据比例计算目标高度
                Mat resizedImage = new Mat();
                Cv2.Resize(originalImage, resizedImage, new OpenCvSharp.Size(targetWidth, targetHeight));
                // 保存调整大小后的图像
                Cv2.ImWrite($@"{filePath}", resizedImage);

                // 释放图像资源
                originalImage.Dispose();
                resizedImage.Dispose();
                SoftCommon.Log.Write($"压缩成功");
            }

        }
        #endregion
    }
}
